package com.hrbxlh.virtualization.service.impl;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.RuntimeUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.hrbxlh.virtualization.constant.NovncConstant;
import com.hrbxlh.virtualization.constant.RancherConstant;
import com.hrbxlh.virtualization.constant.VolumeConstant;
import com.hrbxlh.virtualization.dao.ContainerMapper;
import com.hrbxlh.virtualization.dao.ContainerMapperExt;
import com.hrbxlh.virtualization.dto.ContainerDTO;
import com.hrbxlh.virtualization.dto.FlavorDTO;
import com.hrbxlh.virtualization.enums.ContainerStatusEnum;
import com.hrbxlh.virtualization.exception.GlobalException;
import com.hrbxlh.virtualization.param.ContainerQueryParam;
import com.hrbxlh.virtualization.pojo.Container;
import com.hrbxlh.virtualization.pojo.ContainerExample;
import com.hrbxlh.virtualization.pojo.Image;
import com.hrbxlh.virtualization.result.ResultEnum;
import com.hrbxlh.virtualization.service.ContainerService;
import com.hrbxlh.virtualization.service.DockerService;
import com.hrbxlh.virtualization.util.SSHUtil;
import com.hrbxlh.virtualization.vo.ContainerVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @author cheer
 */
@Service
public class ContainerServiceImpl implements ContainerService {

    private Logger logger = LoggerFactory.getLogger(ContainerServiceImpl.class);

    @Autowired
    private ContainerMapper containerMapper;

    @Autowired
    private ContainerMapperExt containerMapperExt;

    @Autowired
    private DockerService dockerService;

    @Override
    @SuppressWarnings("unchecked")
    public PageInfo<ContainerVO> listContainersByPage(Integer pageNum, Integer pageSize, ContainerQueryParam containerQueryParam) {
        containerQueryParam.trimToNull();

        PageHelper.startPage(pageNum, pageSize);
        List<ContainerDTO> containerDTOList = containerMapperExt.listContainerDTOs(containerQueryParam);
        PageInfo pageInfo = new PageInfo(containerDTOList);

        List<ContainerVO> containerVOList = new ArrayList<>();
        for (ContainerDTO containerDTO : containerDTOList) {
            ContainerVO containerVO = containerDTO.convertToContainerVO();
            containerVOList.add(containerVO);
        }
        pageInfo.setList(containerVOList);
        return pageInfo;
    }

    @Override
    public void deleteContainers(List<Long> containerIdList) {
        List<Container> containerList = listContainersByIds(containerIdList);

        List<String> deleteErrorContainerNameList = new ArrayList<>();
        for (Container container : containerList) {
            try {
                deleteContainer(container);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                deleteErrorContainerNameList.add(container.getRancherId());
            }
        }

        if (CollectionUtils.isNotEmpty(deleteErrorContainerNameList)) {
            String deleteErrorContainerNames = Joiner.on(",").join(deleteErrorContainerNameList);
            throw new GlobalException(ResultEnum.CONTAINERS_DELETE_ERROR.fillArgs(deleteErrorContainerNames));
        }
    }

    private List<Container> listContainersByIds(List<Long> containerIdList) {
        if (CollectionUtils.isEmpty(containerIdList)) {
            return new ArrayList<>();
        }

        ContainerExample containerExample = new ContainerExample();
        containerExample.or().andIdIn(containerIdList);
        return containerMapper.selectByExample(containerExample);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void deleteContainer(Container container) {
        if (container == null || container.getId() == null || StringUtils.isBlank(container.getRancherId())) {
            return;
        }

        dockerService.deleteContainer(container.getRancherId());
        containerMapper.deleteByPrimaryKey(container.getId());
    }

    @Override
    public void deleteAllContainers() {
        deleteContainers(containerMapperExt.listContainerIds());
    }

    @Override
    public Container createContainer(Image image) {
        return createContainer(image, null, null, null);
    }

    @Override
    public Container createContainer(Image image, String hostname) {
        return createContainer(image, null, null, hostname);
    }

    @Override
    public Container createContainer(Image image, String volumeName, FlavorDTO flavorDTO, String hostname) {
        Container container = dockerService.createContainer(image.getDockerName(), volumeName, flavorDTO, hostname);
        container.setImageId(image.getId());
        container.setContainerStatus(ContainerStatusEnum.RUNNING.getCode());
        return container;
    }

    @Override
    public void deleteContainerById(Long containerId) {
        Container container = containerMapper.selectByPrimaryKey(containerId);
        deleteContainer(container);
    }

    @Override
    public boolean startContainer(Container container) {
        try {
            dockerService.startContainer(container.getRancherId());
            container.setContainerStatus(ContainerStatusEnum.RUNNING.getCode());
            containerMapper.updateByPrimaryKeySelective(container);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void deleteContainerFile(String stuorteaId) {
        try {
            RuntimeUtil.execForStr("rm -rf " + VolumeConstant.NFS_DIR + "/" + stuorteaId + "-*");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    public void deleteContainerByCourse(String stuorteaId, Integer courseId, Integer chapterId) {
        ContainerExample example = new ContainerExample();
        example.or().andStuorteaIdEqualTo(stuorteaId)
                .andCourseIdEqualTo(courseId)
                .andChapterIdEqualTo(chapterId);
        List<Container> containerList = containerMapper.selectByExample(example);
        
        if(CollectionUtils.isNotEmpty(containerList)){
            for (Container container : containerList) {
                deleteContainer(container);
            }
        }
    }
}
